
use jsonwebtoken::{decode, encode, get_current_timestamp, DecodingKey, EncodingKey, Header, Validation};
use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize};
use jsonwebtoken::errors::Error as JwtError;

const EXP_TIME: u64 = 604800; // 七天的秒数
// 盐
static KEYS: Lazy<Keys> = Lazy::new(|| {
    let secret = std::env::var("JWT_SECRET").expect("必须设置JWT_SECRET");
    Keys::new(secret.as_bytes())      
});

struct Keys {
    encoding: EncodingKey,
    decoding: DecodingKey,
}

impl Keys {
    fn new(secret: &[u8]) -> Self {
        Self {
            encoding: EncodingKey::from_secret(secret),
            decoding: DecodingKey::from_secret(secret),
        }
    }
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Claims {
    pub account: String,  // 账号
    pub username: String, // 用户名
    pub exp: u64,         // 过期时间
    pub iat: u64,         // 签发时间
}

impl Claims {
    pub fn new(account: String, username: String) -> Claims {
        let time = get_current_timestamp();
        Claims {
            account,
            username,
            exp: EXP_TIME + time,
            iat: time,
        }
    }
}

// 加密token
pub fn create_token(claims: &Claims) -> String {
    encode(&Header::default(), claims, &KEYS.encoding).expect("生成token失败")
}

// 解密token
pub fn decode_token(token: &str) -> Result<Claims, JwtError> {
    decode::<Claims>(token, &KEYS.decoding, &Validation::default())
       .map(|data| data.claims)
}

// 是否过期
pub fn is_token_expired(token: &str) -> bool {
    match decode_token(token) {
        Ok(claims) => get_current_timestamp() > claims.exp,
        Err(_) => true,
    }
}